﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Collections.Concurrent;

namespace Txt2PajekLarge
{
    public partial class frmMain : Form
    {
        private DataLoader oDataLoader = new DataLoader();
        private DataSaver oDataSaver = new DataSaver();
        private bool blnStopManually = false;

        private void ShowSettings(SettingItems settings)
        {
            if (settings.BufferedIn == BufferIn.BUFFER_IN_MEM)
            {
                rdBufferInMem.Checked = true;
                gpDBOptions.Enabled = false;
            }
            else
            {
                rdBufferInDB.Checked = true;
                gpDBOptions.Enabled = true;

                if (settings.DBType == "SQL Server")
                    drplstDBType.SelectedIndex = 0;
                else
                    drplstDBType.SelectedIndex = 1;
                txtDBServer.Text = settings.DBServer;
                txtDBUserName.Text = settings.DBUserName;
                txtDBPwd.Text = settings.DBPwd;
                txtDBName.Text = settings.DBName;
            }

            if (settings.WeightOnEdge) rdWeight.Checked = true;
            else rdNoWeight.Checked = true;

            switch (settings.Splitter)
            {
                case SplitterChar.SPACE:
                    rdSpace.Checked = true;
                    break;
                case SplitterChar.LINE:
                    rdLine.Checked = true;
                    break;
                default:
                    rdTab.Checked = true;
                    break;
            }

            if (settings.Directed) rdDirected.Checked = true;
            else rdUndirected.Checked = true;

            chkIgnoreFirstLine.Checked = settings.Ignore1stLine;
            chkGenerateFinalFile.Checked = settings.GenerateFinalFile;

            if (settings.NodeIDStartFrom == 0) rdZero.Checked = true;
            else rdOne.Checked = true;
        }

        private void LoadSettings()
        {
            GlobalPool.Settings = AppSettings.Load();
            if (GlobalPool.Settings == null)
            {
                MessageBox.Show("Reading Config File Error! Default settings will be loaded.", "Txt2PajekLarge");
                GlobalPool.Settings = AppSettings.LoadDefault();
            }
            ShowSettings(GlobalPool.Settings);
        }

        public frmMain()
        {
            InitializeComponent();
        }

        private void btnTransform_Click(object sender, EventArgs e)
        {
            if (rdBufferInDB.Checked)
            {
                string strDataBaseStatus = PubHelper.TestDataBase();
                if (strDataBaseStatus != "OK")
                {
                    MessageBox.Show("DataBase Error: " + strDataBaseStatus, "Txt2PajekLarge");
                    return;
                }
            }
            oDataLoader.AsyncWorker = bgwFileReader;
            oDataSaver.AsyncWorkerNodeList = bgwNodeWriter;
            oDataSaver.AsyncWriterEdgeList = bgwEdgeWriter;
            oDataSaver.AsyncWriterFinalFile = bgwFinalFile;

            if (bgwFileReader.IsBusy || bgwNodeWriter.IsBusy || bgwEdgeWriter.IsBusy || bgwFinalFile.IsBusy)
            {
                //to stop
                bool blnStateLoader = oDataLoader.Suspending;
                oDataLoader.Suspending = true;
                bool blnStateSaver = oDataSaver.Suspending;
                oDataSaver.Suspending = true;
                if (MessageBox.Show("Are you sure to stop transforming?", "Txt2PajekLarge", MessageBoxButtons.YesNo) == DialogResult.No)
                {
                    oDataLoader.Suspending = blnStateLoader;
                    oDataSaver.Suspending = blnStateSaver;
                    return;
                }
                oDataLoader.AsyncCancelled = true;
                oDataSaver.AsyncCancelled = true;

                GlobalPool.NodeList.CompleteAdding();
                GlobalPool.EdgeList.CompleteAdding();

                blnStopManually = true;

                //stop transforming
                bgwFileReader.CancelAsync();
                bgwNodeWriter.CancelAsync();
                bgwEdgeWriter.CancelAsync();
                bgwFinalFile.CancelAsync();
            }
            else
            {
                //to start
                btnSelectFile.Enabled = false;
                gpOptions.Enabled = false;

                RecordSettings();

                btnTransform.Text = "Stop Transforming";
                btnPauseContinue.Text = "Pause";
                btnPauseContinue.Enabled = true;

                blnStopManually = false;

                if (GlobalPool.NodeList != null) GlobalPool.NodeList.Dispose();
                if (GlobalPool.EdgeList != null) GlobalPool.EdgeList.Dispose();
                GlobalPool.NodeList = new BlockingCollection<Node>(new ConcurrentQueue<Node>());
                GlobalPool.EdgeList= new BlockingCollection<Edge>(new ConcurrentQueue<Edge>());

                //start transforming
                bgwFileReader.RunWorkerAsync();
                bgwNodeWriter.RunWorkerAsync();
                bgwEdgeWriter.RunWorkerAsync();
            }
        }

        private void btnSelectFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlgText = new OpenFileDialog();
            dlgText.Filter = "所有文件|*.*";
            if (dlgText.ShowDialog() == DialogResult.OK)
            {
                lblFileName.Text = dlgText.FileName;
                oDataLoader.FileName = dlgText.FileName;
                GlobalPool.SourceFileName = dlgText.SafeFileName.Split('.')[0];
                btnTransform.Enabled = true;
            }
        }

        private void btnPauseContinue_Click(object sender, EventArgs e)
        {
            if (btnPauseContinue.Text == "Pause")
                btnPauseContinue.Text = "Continue";
            else
                btnPauseContinue.Text = "Pause";

            oDataLoader.Suspending = !oDataLoader.Suspending;
            oDataSaver.Suspending = !oDataSaver.Suspending;
        }

        private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!CanBeClosed()) e.Cancel = true;
        }

        private bool CanBeClosed()
        {
            if (!oDataLoader.AsyncCancelled || !oDataSaver.AsyncCancelled)
            {
                oDataLoader.Suspending = true;
                oDataSaver.Suspending = true;
                if (MessageBox.Show("The Transformer is working, are you sure to stop it and exit?", "Txt2PajekLarge", MessageBoxButtons.YesNo) == DialogResult.No)
                {
                    oDataLoader.Suspending = false;
                    oDataSaver.Suspending = false;
                    return false;
                }
            }
            return true;
        }

        private void btnExit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void btnDefault_Click(object sender, EventArgs e)
        {
            SettingItems settings = AppSettings.LoadDefault();
            ShowSettings(settings);
        }

        private void btnLoad_Click(object sender, EventArgs e)
        {
            LoadSettings();
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            RecordSettings();

            AppSettings.Save(GlobalPool.Settings);

            MessageBox.Show("Settings have been saved.", "Txt2PajekLarge");
        }

        private void RecordSettings()
        {
            if (GlobalPool.Settings == null)
                GlobalPool.Settings = new SettingItems();

            if (rdBufferInMem.Checked)
                GlobalPool.Settings.BufferedIn = BufferIn.BUFFER_IN_MEM;
            else
            {
                GlobalPool.Settings.BufferedIn = BufferIn.BUFFER_IN_DB;
                GlobalPool.Settings.DBType = drplstDBType.SelectedItem.ToString();
                GlobalPool.Settings.DBServer = txtDBServer.Text.Trim();
                GlobalPool.Settings.DBUserName = txtDBUserName.Text.Trim();
                GlobalPool.Settings.DBPwd = txtDBPwd.Text.Trim();
                GlobalPool.Settings.DBName = txtDBName.Text.Trim();
            }
            GlobalPool.Settings.WeightOnEdge = rdWeight.Checked;
            if (rdTab.Checked) GlobalPool.Settings.Splitter = SplitterChar.TAB;
            else if (rdSpace.Checked) GlobalPool.Settings.Splitter = SplitterChar.SPACE;
            else GlobalPool.Settings.Splitter = SplitterChar.LINE;
            GlobalPool.Settings.Directed = rdDirected.Checked;
            GlobalPool.Settings.Ignore1stLine = chkIgnoreFirstLine.Checked;
            GlobalPool.Settings.GenerateFinalFile = chkGenerateFinalFile.Checked;
            if (rdZero.Checked)
                GlobalPool.Settings.NodeIDStartFrom = 0;
            else
                GlobalPool.Settings.NodeIDStartFrom = 1;
        }

        private void rdBufferInDB_CheckedChanged(object sender, EventArgs e)
        {
            gpDBOptions.Enabled = true;
        }

        private void rdBufferInMem_CheckedChanged(object sender, EventArgs e)
        {
            gpDBOptions.Enabled = false;
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            drplstDBType.SelectedIndex = 0;
            LoadSettings();
        }

        private void bgwFileReader_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                oDataLoader.LoadData();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error occured when loading data!\n" + ex.InnerException + "\n" + ex.Message + "\n" + ex.Source + "\n" + ex.StackTrace + "\n" + ex.TargetSite);
                //stop loading data
                GlobalPool.NodeList.CompleteAdding();
                GlobalPool.EdgeList.CompleteAdding();
                oDataLoader.AsyncCancelled = true;
                bgwFileReader.CancelAsync();
            }
        }

        private void bgwFileReader_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            lblDataLoaderMessage.Text = e.UserState.ToString();
        }

        private void bgwFileReader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(this, e.Error.Message);
                return;
            }
            GlobalPool.NodeList.CompleteAdding();
            GlobalPool.EdgeList.CompleteAdding();
            if (!bgwNodeWriter.IsBusy && !bgwEdgeWriter.IsBusy && !bgwFinalFile.IsBusy)
            {
                btnSelectFile.Enabled = true;
                gpOptions.Enabled = true;

                btnTransform.Text = "Start Transforming";
                btnPauseContinue.Text = "Pause / Continue";
                btnPauseContinue.Enabled = false;
            }
        }

        private void bgwNodeWriter_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                oDataSaver.SaveNodes();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error occured when saving nodes!\n" + ex.InnerException + "\n" + ex.Message + "\n" + ex.Source + "\n" + ex.StackTrace + "\n" + ex.TargetSite);
                //stop loading data
                oDataSaver.AsyncCancelled = true;
                bgwNodeWriter.CancelAsync();
            }
        }

        private void bgwNodeWriter_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            lblNodeWriterMessage.Text = e.UserState.ToString();
        }

        private void bgwNodeWriter_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(this, e.Error.Message);
                return;
            }

            if (!blnStopManually && !bgwEdgeWriter.IsBusy && GlobalPool.Settings.GenerateFinalFile)
                bgwFinalFile.RunWorkerAsync();
            if (!bgwFileReader.IsBusy && !bgwEdgeWriter.IsBusy && !bgwFinalFile.IsBusy)
            {
                btnSelectFile.Enabled = true;
                gpOptions.Enabled = true;

                btnTransform.Text = "Start Transforming";
                btnPauseContinue.Text = "Pause / Continue";
                btnPauseContinue.Enabled = false;
            }
        }

        private void bgwEdgeWriter_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                oDataSaver.SaveEdges();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error occured when saving edges!\n" + ex.InnerException + "\n" + ex.Message + "\n" + ex.Source + "\n" + ex.StackTrace + "\n" + ex.TargetSite);
                //stop loading data
                oDataSaver.AsyncCancelled = true;
                bgwEdgeWriter.CancelAsync();
            }
        }

        private void bgwEdgeWriter_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            lblEdgeWriterMessage.Text = e.UserState.ToString();
        }

        private void bgwEdgeWriter_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(this, e.Error.Message);
                return;
            }

            if (!blnStopManually && !bgwNodeWriter.IsBusy && GlobalPool.Settings.GenerateFinalFile)
                bgwFinalFile.RunWorkerAsync();
            if (!bgwFileReader.IsBusy && !bgwNodeWriter.IsBusy && !bgwFinalFile.IsBusy)
            {
                btnSelectFile.Enabled = true;
                gpOptions.Enabled = true;

                btnTransform.Text = "Start Transforming";
                btnPauseContinue.Text = "Pause / Continue";
                btnPauseContinue.Enabled = false;
            }
        }

        private void bgwFinalFile_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                oDataSaver.GenerateFinalFile();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error occured when generating final file!\n" + ex.InnerException + "\n" + ex.Message + "\n" + ex.Source + "\n" + ex.StackTrace + "\n" + ex.TargetSite);
                oDataSaver.AsyncCancelled = true;
                bgwFinalFile.CancelAsync();
            }
        }

        private void bgwFinalFile_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            lblEdgeWriterMessage.Text = e.UserState.ToString();
        }

        private void bgwFinalFile_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(this, e.Error.Message);
                return;
            }

            btnSelectFile.Enabled = true;
            gpOptions.Enabled = true;

            btnTransform.Text = "Start Transforming";
            btnPauseContinue.Text = "Pause / Continue";
            btnPauseContinue.Enabled = false;
        }
    }
}
